package org.budo.weixin.work.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.budo.support.assertion.Assert;
import org.budo.support.lang.util.NumberUtil;
import org.budo.support.lang.util.StringUtil;
import org.budo.support.lang.util.UuidUtil;
import org.budo.support.slf4j.Slf4j;
import org.budo.time.Time;
import org.budo.weixin.event.ChangeContactEvent;
import org.budo.weixin.event.ClickEvent;
import org.budo.weixin.event.LocationEvent;
import org.budo.weixin.event.SubscribeEvent;
import org.budo.weixin.event.UnSubscribeEvent;
import org.budo.weixin.message.Article;
import org.budo.weixin.message.ImageMessage;
import org.budo.weixin.message.LinkMessage;
import org.budo.weixin.message.LocationMessage;
import org.budo.weixin.message.Message;
import org.budo.weixin.message.NewsMessage;
import org.budo.weixin.message.ShortVideoMessage;
import org.budo.weixin.message.TextMessage;
import org.budo.weixin.message.VideoMessage;
import org.budo.weixin.message.VoiceMessage;
import org.budo.weixin.work.TaskCardMessage;
import org.budo.weixin.work.WorkWeixinMessage;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;

import com.alibaba.fastjson.JSONObject;

/**
 * @author li
 * @version 1 (2015年10月12日 上午11:29:07)
 * @since Java7
 */
public class WorkWeixinMessageUtil {
    private static final Logger log = Slf4j.getLogger();

    /**
     * @see #fromWeixinMessage(Message)
     * @see #toWeixinMessage(WorkWeixinMessage)
     * @see #toJson(WorkWeixinMessage)
     */
    public static WorkWeixinMessage fromXml(String decryptMessage) {
        try {
            Document document = Jsoup.parse(decryptMessage);
            Elements xml = document.select("xml");

            WorkWeixinMessage workWeixinMessage = new WorkWeixinMessage();

            workWeixinMessage.setToUserName(xml.select("ToUserName").text());
            workWeixinMessage.setFromUserName(xml.select("FromUserName").text());
            workWeixinMessage.setCreateTime(NumberUtil.toLong(xml.select("CreateTime").text()));
            workWeixinMessage.setMessageType(xml.select("MsgType").text());
            workWeixinMessage.setMessageId(xml.select("MsgId").text());
            workWeixinMessage.setAgentId(xml.select("AgentID").text());

            workWeixinMessage.setContent(xml.select("Content").text());

            workWeixinMessage.setPicUrl(xml.select("PicUrl").text());
            workWeixinMessage.setMediaId(xml.select("MediaId").text());

            workWeixinMessage.setFormat(xml.select("Format").text());

            workWeixinMessage.setThumbMediaId(xml.select("ThumbMediaId").text());

            workWeixinMessage.setLocationX(xml.select("Location_X").text());
            workWeixinMessage.setLocationY(xml.select("Location_Y").text());
            workWeixinMessage.setScale(xml.select("Scale").text());
            workWeixinMessage.setLabel(xml.select("Label").text());

            workWeixinMessage.setEvent(xml.select("Event").text());
            workWeixinMessage.setEventKey(xml.select("EventKey").text());

            workWeixinMessage.setScanType(xml.select("ScanType").text());
            workWeixinMessage.setScanResult(xml.select("ScanResult").text());

            workWeixinMessage.setLatitude(xml.select("Latitude").text());
            workWeixinMessage.setLongitude(xml.select("Longitude").text());
            workWeixinMessage.setPrecision(xml.select("Precision").text());
            workWeixinMessage.setUrl(xml.select("Url").text());
            workWeixinMessage.setTitle(xml.select("Title").text());
            workWeixinMessage.setDescription(xml.select("Description").text());

            // http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6
            // 弹出系统拍照发图的事件推送 不支持
            // 弹出拍照或者相册发图的事件推送 不支持
            // 弹出微信相册发图器的事件推送 不支持
            // 弹出地理位置选择器的事件推送 不支持
            // 异步任务完成事件推送 不支持

            workWeixinMessage.setChangeType(xml.select("ChangeType").text());
            workWeixinMessage.setAvatar(xml.select("Avatar").text());
            workWeixinMessage.setUserID(xml.select("UserID").text());
            workWeixinMessage.setNewUserID(xml.select("NewUserID").text());
            workWeixinMessage.setName(xml.select("Name").text());
            workWeixinMessage.setMobile(xml.select("Mobile").text());
            workWeixinMessage.setPosition(xml.select("Position").text());
            workWeixinMessage.setGender(xml.select("Gender").text());
            workWeixinMessage.setEmail(xml.select("Email").text());
            workWeixinMessage.setStatus(xml.select("Status").text());
            workWeixinMessage.setEnglishName(xml.select("EnglishName").text());
            workWeixinMessage.setIsLeader(xml.select("IsLeader").text());
            workWeixinMessage.setTelephone(xml.select("Telephone").text());

            // 部门ID
            Integer[] departmentIds = readDepartmentIds(xml);
            workWeixinMessage.setDepartment(departmentIds);

            // 新增部门的部门Id
            String idValue = xml.select("Id").text();
            Integer id = NumberUtil.toInteger(idValue);
            workWeixinMessage.setId(id);

            Elements extAttrNode = xml.select("ExtAttr");
            List<Map<String, String>> extAttr = new ArrayList<Map<String, String>>();
            Map<String, String> ext = null;
            for (Element element : extAttrNode) {
                ext = new HashMap<String, String>();
                ext.put("name", element.attr("Name"));
                ext.put("value", element.attr("Value"));
                extAttr.add(ext);
            }
            workWeixinMessage.setExtAttr(extAttr);

            return workWeixinMessage;
        } catch (Throwable e) {
            String message = "#133 fromXml error " + e + ", decryptMessage=" + decryptMessage;
            log.error(message, e);
            throw new RuntimeException(message, e);
        }
    }

    private static Integer[] readDepartmentIds(Elements xml) {
        if (null == xml) {
            log.error("#133 xml=" + xml);
            return null;
        }

        Elements department = xml.select("Department");
        if (null == department) {
            return null;
        }

        String departmentText = department.text();
        if (null == departmentText) {
            return null;
        }

        if (departmentText.trim().isEmpty()) {
            return new Integer[0];
        }

        String[] departmentIds = departmentText.split(",");
        return NumberUtil.toIntegerArray(departmentIds);
    }

    public static String toJson(TaskCardMessage taskCardMessage) {
        String taskId = taskCardMessage.getTaskId();
        if (StringUtil.isEmpty(taskId)) {
            taskId = UuidUtil.randomUuid();
        }

        return "{\"touser\":\"" + taskCardMessage.getToUserName() + "\",\"msgtype\":\"taskcard\",\"agentid\":" + taskCardMessage.getAgentId() + "," //
                + "\"taskcard\":{" //
                + "\"title\":\"测试消息-黎明伟-" + Time.now().toString("yyyyMMdd.HHmmss.SSS") + "\"," //
                + "\"description\":\"测试消息内容-黎明伟-" + Time.now().toString("yyyyMMdd.HHmmss.SSS") + "\"," //
                + "\"url\":\"http://t.tt\"," //
                + "\"task_id\":\"" + taskId + "\"," //
                + "\"btn\":[" //
                + "{\"key\":\"key111\",\"name\":\"批准\",\"replace_name\":\"已批准\",\"color\":\"red\",\"is_bold\":true}," //
                + "{\"key\":\"key222\",\"name\":\"驳回\",\"replace_name\":\"已驳回\"}" //
                + "]}}";
    }

    /**
     * @see #fromWeixinMessage(Message)
     * @see #fromXml(String)
     * @see #toWeixinMessage(WorkWeixinMessage)
     * @see org.budo.weixin.util.WeixinUtil#messageToJson(Message)
     */
    public static String toJson(WorkWeixinMessage message) {
        if (WorkWeixinMessage.TYPE_TEXT.equalsIgnoreCase(message.getMessageType())) {
            return "{ \"touser\": \"" + message.getToUserName() + "\", \"msgtype\": \"text\", \"agentid\": \"" + message.getAgentId() + "\", \"text\": { \"content\": \"" + message.getContent() + "\" }}";
        } else if (WorkWeixinMessage.TYPE_IMAGE.equalsIgnoreCase(message.getMessageType())) {
            return "{ \"touser\": \"" + message.getToUserName() + "\", \"msgtype\": \"image\", \"agentid\": \"" + message.getAgentId() + "\", \"image\": { \"media_id\": \"" + message.getMediaId() + "\" }, \"safe\":\"0\" }";
        } else if (WorkWeixinMessage.TYPE_VOICE.equalsIgnoreCase(message.getMessageType())) {
            return "{ \"touser\": \"" + message.getToUserName() + "\", \"msgtype\": \"voice\", \"agentid\": \"" + message.getAgentId() + "\", \"voice\": { \"media_id\": \"" + message.getMediaId() + "\" }, \"safe\":\"0\" }";
        } else if (WorkWeixinMessage.TYPE_VIDEO.equalsIgnoreCase(message.getMessageType())) {
            JSONObject obj = new JSONObject();
            obj.put("touser", message.getToUserName());
            obj.put("msgtype", "video");
            obj.put("agentid", message.getAgentId());

            JSONObject video = new JSONObject();
            video.put("media_id", message.getMediaId());
            video.put("title", "视频");
            video.put("description", "点击播放");

            obj.put("video", video);
            obj.put("safe", "0");
            return obj.toJSONString();
        } else if (WorkWeixinMessage.TYPE_NEWS.equalsIgnoreCase(message.getMessageType())) {
            List<Article> articles = message.getArticles();
            Assert.notNull(articles, "articles is null");

            String json = "{ \"touser\": \"" + message.getToUserName() + "\", \"msgtype\": \"news\", \"agentid\": \"" + message.getAgentId() + "\", \"news\": { \"articles\":[ ";
            for (int i = 0; i < articles.size(); i++) {
                if (0 < i) {
                    json += ",";
                }
                Article article = articles.get(i);
                json += " { \"title\": \"" + article.getTitle() + "\", \"description\": \"" + article.getDescription() + "\", \"url\": \"" + article.getUrl() + "\", \"picurl\": \"" + article.getPicUrl() + "\" }";
            }
            json += " ] } }";
            return json;
        } else {
            return "{ \"touser\": \"" + message.getToUserName() + "\", \"msgtype\": \"text\", \"agentid\": \"" + message.getAgentId() + "\", \"text\": { \"content\": \"暂未支持[3]的消息类型 " + message.getMessageType() + "\" }}";
        }
    }

    /**
     * 企业号消息转为普通微信消息
     * 
     * @see #fromWeixinMessage(Message)
     * @see #fromXml(String)
     * @see #toJson(WorkWeixinMessage)
     */
    public static Message toWeixinMessage(WorkWeixinMessage workWeixinMessage) {
        Assert.notNull(workWeixinMessage, "workWeixinMessage 为空");

        Message message = null;
        String messageType = StringUtil.trim(workWeixinMessage.getMessageType());
        if (WorkWeixinMessage.TYPE_TEXT.equalsIgnoreCase(messageType)) {
            message = new TextMessage();
            TextMessage textMessage = (TextMessage) message;
            textMessage.setContent(workWeixinMessage.getContent());
        } else if (WorkWeixinMessage.TYPE_IMAGE.equalsIgnoreCase(messageType)) {
            message = new ImageMessage();
            ImageMessage imageMessage = (ImageMessage) message;
            imageMessage.setPicUrl(workWeixinMessage.getPicUrl());
            imageMessage.setMediaId(workWeixinMessage.getMediaId());
        } else if (WorkWeixinMessage.TYPE_VOICE.equalsIgnoreCase(messageType)) {
            message = new VoiceMessage();
            VoiceMessage voiceMessage = (VoiceMessage) message;
            voiceMessage.setMediaId(workWeixinMessage.getMediaId());
        } else if (WorkWeixinMessage.TYPE_VIDEO.equalsIgnoreCase(messageType)) {
            message = new VideoMessage();
            VideoMessage videoMessage = (VideoMessage) message;
            videoMessage.setMediaId(workWeixinMessage.getMediaId());
        } else if (WorkWeixinMessage.TYPE_SHORT_VIDEO.equalsIgnoreCase(messageType)) {
            message = new ShortVideoMessage();
            ShortVideoMessage shortVideoMessage = (ShortVideoMessage) message;
            shortVideoMessage.setMediaId(workWeixinMessage.getMediaId());
        } else if (WorkWeixinMessage.TYPE_LOCATION.equalsIgnoreCase(messageType)) {
            message = new LocationMessage();
            LocationMessage locationMessage = (LocationMessage) message;
            locationMessage.setLocationX(workWeixinMessage.getLocationX());
            locationMessage.setLocationY(workWeixinMessage.getLocationY());
            locationMessage.setScale(workWeixinMessage.getScale());
            locationMessage.setLabel(workWeixinMessage.getLabel());
        } else if (WorkWeixinMessage.TYPE_EVENT.equalsIgnoreCase(messageType)) {
            String event = StringUtil.trim(workWeixinMessage.getEvent());
            if (WorkWeixinMessage.EVENT_CLICK.equalsIgnoreCase(event)) {
                message = new ClickEvent();
                ClickEvent clickEvent = (ClickEvent) message;
                clickEvent.setEventKey(workWeixinMessage.getEventKey());
            } else if (WorkWeixinMessage.EVENT_SUBSCRIBE.equalsIgnoreCase(event)) {
                message = new SubscribeEvent();
            } else if (WorkWeixinMessage.EVENT_UNSUBSCRIBE.equalsIgnoreCase(event)) {
                message = new UnSubscribeEvent();
            } else if (WorkWeixinMessage.EVENT_CHANGE_CONTANCT.equalsIgnoreCase(event)) {
                message = toChangeContactEvent(workWeixinMessage);
            } else if (WorkWeixinMessage.EVENT_LOCATION.equalsIgnoreCase(event)) {
                message = toLocationEvent(workWeixinMessage);
            } else {
                message = new TextMessage();
                TextMessage textMessage = (TextMessage) message;
                textMessage.setContent("暂时未支持[2.1]的事件类型：" + workWeixinMessage.getMessageType() + " " + workWeixinMessage.getEvent());
            }
        } else if (WorkWeixinMessage.LINK.equalsIgnoreCase(messageType)) {
            message = new LinkMessage();
            ((LinkMessage) message).setTitle(workWeixinMessage.getTitle());
            ((LinkMessage) message).setDescription(workWeixinMessage.getDescription());
            ((LinkMessage) message).setUrl(workWeixinMessage.getUrl());
        } else {
            message = new TextMessage();
            TextMessage textMessage = (TextMessage) message;
            textMessage.setContent("暂时未支持[2]的消息类型：" + workWeixinMessage.getMessageType());
        }

        message.setId(workWeixinMessage.getMessageId());
        message.setCreateTime(workWeixinMessage.getCreateTime());
        message.setFrom(workWeixinMessage.getFromUserName());
        message.setTo(workWeixinMessage.getToUserName());
        return message;
    }

    private static Message toLocationEvent(WorkWeixinMessage workWeixinMessage) {
        LocationEvent message = new LocationEvent();
        message.setCreateTime(workWeixinMessage.getCreateTime());
        message.setEventKey(workWeixinMessage.getEventKey());
        message.setLatitude(workWeixinMessage.getLatitude());
        message.setLongitude(workWeixinMessage.getLongitude());
        message.setPrecision(workWeixinMessage.getPrecision());
        return message;
    }

    private static Message toChangeContactEvent(WorkWeixinMessage workWeixinMessage) {
        ChangeContactEvent message = new ChangeContactEvent();
        message.setAvatar(workWeixinMessage.getAvatar());
        message.setChangeType(workWeixinMessage.getChangeType());
        message.setDepartment(workWeixinMessage.getDepartment());
        message.setEmail(workWeixinMessage.getEmail());
        message.setEnglishName(workWeixinMessage.getEnglishName());
        message.setExtAttr(workWeixinMessage.getExtAttr());
        message.setGender(workWeixinMessage.getGender());
        message.setIsLeader(workWeixinMessage.getIsLeader());
        message.setMobile(workWeixinMessage.getMobile());
        message.setName(workWeixinMessage.getName());
        message.setNewUserID(workWeixinMessage.getNewUserID());
        message.setPosition(workWeixinMessage.getPosition());
        message.setStatus(workWeixinMessage.getStatus());
        message.setTelephone(workWeixinMessage.getTelephone());
        message.setUserID(workWeixinMessage.getUserID());
        return message;
    }

    /**
     * @see #fromXml(String)
     * @see #toWeixinMessage(WorkWeixinMessage)
     * @see #toJson(WorkWeixinMessage)
     */
    public static WorkWeixinMessage fromWeixinMessage(Message message) {
        Assert.notNull(message, "message 为空");

        WorkWeixinMessage workWeixinMessage = new WorkWeixinMessage();
        workWeixinMessage.setMessageId(message.getId());
        workWeixinMessage.setFromUserName(message.getFrom());
        workWeixinMessage.setToUserName(message.getTo());
        workWeixinMessage.setCreateTime(message.getCreateTime());
        workWeixinMessage.setMessageType(message.getType());

        if (message instanceof TextMessage) {
            TextMessage textMessage = (TextMessage) message;
            workWeixinMessage.setContent(textMessage.getContent());
        } else if (message instanceof ImageMessage) {
            ImageMessage imageMessage = (ImageMessage) message;
            workWeixinMessage.setPicUrl(imageMessage.getPicUrl());
            workWeixinMessage.setMediaId(imageMessage.getMediaId());
        } else if (message instanceof VoiceMessage) {
            VoiceMessage voiceMessage = (VoiceMessage) message;
            workWeixinMessage.setMediaId(voiceMessage.getMediaId());
        } else if (message instanceof VideoMessage) {
            VideoMessage videoMessage = (VideoMessage) message;
            workWeixinMessage.setMediaId(videoMessage.getMediaId());
        } else if (message instanceof NewsMessage) {
            NewsMessage newsMessage = (NewsMessage) message;
            workWeixinMessage.setArticles(newsMessage.getArticles());
        } else { // 其他类型
            workWeixinMessage.setMessageType(WorkWeixinMessage.TYPE_TEXT);
            workWeixinMessage.setContent("暂时未支持[1]的消息类型 " + message.getType());
        }
        return workWeixinMessage;
    }
}